home *** CD-ROM | disk | FTP | other *** search
/ Aminet 31 / Aminet 31 (1999)(Schatztruhe)[!][Jun 1999].iso / Aminet / dev / cross / z88dk_v1.0s.lha / src / cpp / cpp6.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  27.4 KB  |  989 lines

  1. /*
  2.  *                C P P 6 . C
  3.  *        S u p p o r t   R o u t i n e s
  4.  *
  5.  * Edit History
  6.  * 25-May-84 MM        Added 8-bit support to type table.
  7.  * 30-May-84 ARF    sharp() should output filename in quotes
  8.  * 02-Aug-84 MM        Newline and #line hacking.  sharp() now in cpp1.c
  9.  * 31-Aug-84 MM        USENET net.sources release
  10.  * 11-Sep-84 ado/MM    Keepcomments, also line number pathological
  11.  * 12-Sep-84 ado/MM    bug if comment changes to space and we unget later.
  12.  * 03-Oct-84 gkr/MM    Fixed scannumber bug for '.e' (as in struct.element).
  13.  * 04-Oct-84 MM        Added ungetstring() for token concatenation
  14.  * 08-Oct-84 MM        Yet another attack on number scanning
  15.  * 31-Oct-84 ado    Parameterized $ in identifiers
  16.  *  2-Nov-84 MM        Token concatenation is messier than I thought
  17.  *  6-Dec-84 MM        \<nl> is everywhere invisible.
  18.  */
  19.  
  20. #include    <stdio.h>
  21. #include    <ctype.h>
  22. #include    "cppdef.h"
  23. #include    "cpp.h"
  24.  
  25. /*
  26.  * skipnl()    skips over input text to the end of the line.
  27.  * skipws()    skips over "whitespace" (spaces or tabs), but
  28.  *        not skip over the end of the line.  It skips over
  29.  *        TOK_SEP, however (though that shouldn't happen).
  30.  * scanid()    reads the next token (C identifier) into token[].
  31.  *        The caller has already read the first character of
  32.  *        the identifier.  Unlike macroid(), the token is
  33.  *        never expanded.
  34.  * macroid()    reads the next token (C identifier) into token[].
  35.  *        If it is a #defined macro, it is expanded, and
  36.  *        macroid() returns TRUE, otherwise, FALSE.
  37.  * catenate()    Does the dirty work of token concatenation, TRUE if it did.
  38.  * scanstring()    Reads a string from the input stream, calling
  39.  *        a user-supplied function for each character.
  40.  *        This function may be output() to write the
  41.  *        string to the output file, or save() to save
  42.  *        the string in the work buffer.
  43.  * scannumber()    Reads a C numeric constant from the input stream,
  44.  *        calling the user-supplied function for each
  45.  *        character.  (output() or save() as noted above.)
  46.  * save()    Save one character in the work[] buffer.
  47.  * savestring()    Saves a string in malloc() memory.
  48.  * getfile()    Initialize a new FILEINFO structure, called when
  49.  *        #include opens a new file, or a macro is to be
  50.  *        expanded.
  51.  * getmem()    Get a specified number of bytes from malloc memory.
  52.  * output()    Write one character to stdout (calling putchar) --
  53.  *        implemented as a function so its address may be
  54.  *        passed to scanstring() and scannumber().
  55.  * lookid()    Scans the next token (identifier) from the input
  56.  *        stream.  Looks for it in the #defined symbol table.
  57.  *        Returns a pointer to the definition, if found, or NULL
  58.  *        if not present.  The identifier is stored in token[].
  59.  * defnedel()    Define enter/delete subroutine.  Updates the
  60.  *        symbol table.
  61.  * get()    Read the next byte from the current input stream,
  62.  *        handling end of (macro/file) input and embedded
  63.  *        comments appropriately.  Note that the global
  64.  *        instring is -- essentially -- a parameter to get().
  65.  * cget()    Like get(), but skip over TOK_SEP.
  66.  * unget()    Push last gotten character back on the input stream.
  67.  * cerror(), cwarn(), cfatal(), cierror(), ciwarn()
  68.  *        These routines format an print messages to the user.
  69.  *        cerror & cwarn take a format and a single string argument.
  70.  *        cierror & ciwarn take a format and a single int (char) argument.
  71.  *        cfatal takes a format and a single string argument.
  72.  */
  73.  
  74. /*
  75.  * This table must be rewritten for a non-Ascii machine.
  76.  *
  77.  * Note that several "non-visible" characters have special meaning:
  78.  * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion.
  79.  * Hex 1E TOK_SEP   -- a delimiter for token concatenation
  80.  * Hex 1F COM_SEP   -- a zero-width whitespace for comment concatenation
  81.  */
  82. #if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D
  83. #error "<< error type table isn't correct >>"
  84. #endif
  85.  
  86. #if OK_DOLLAR
  87. #define    DOL    LET
  88. #else
  89. #define    DOL    000
  90. #endif
  91.  
  92. char type[256] = {        /* Character type codes    Hex        */
  93.    END,   000,   000,   000,   000,   000,   000,   000, /* 00        */
  94.    000,   SPA,   000,   000,   000,   000,   000,   000, /* 08        */
  95.    000,   000,   000,   000,   000,   000,   000,   000, /* 10        */
  96.    000,   000,   000,   000,   000,   LET,   000,   SPA, /* 18        */
  97.    SPA,OP_NOT,   QUO,   000,   DOL,OP_MOD,OP_AND,   QUO, /* 20  !"#$%&'    */
  98. OP_LPA,OP_RPA,OP_MUL,OP_ADD,   000,OP_SUB,   DOT,OP_DIV, /* 28 ()*+,-./    */
  99.    DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG,   DIG, /* 30 01234567    */
  100.    DIG,   DIG,OP_COL,   000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>?    */
  101.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 40 @ABCDEFG    */
  102.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 48 HIJKLMNO    */
  103.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 50 PQRSTUVW    */
  104.    LET,   LET,   LET,   000,   BSH,   000,OP_XOR,   LET, /* 58 XYZ[\]^_    */
  105.    000,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 60 `abcdefg    */
  106.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 68 hijklmno    */
  107.    LET,   LET,   LET,   LET,   LET,   LET,   LET,   LET, /* 70 pqrstuvw    */
  108.    LET,   LET,   LET,   000, OP_OR,   000,OP_NOT,   000, /* 78 xyz{|}~    */
  109.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  110.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  111.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  112.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  113.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  114.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  115.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  116.    000,   000,   000,   000,   000,   000,   000,   000, /*   80 .. FF    */
  117. };
  118.  
  119. skipnl()
  120. /*
  121.  * Skip to the end of the current input line.
  122.  */
  123. {
  124.     register int        c;
  125.  
  126.     do {                /* Skip to newline    */
  127.         c = get();
  128.     } while (c != '\n' && c != EOF_CHAR);
  129. }
  130.  
  131. int
  132. skipws()
  133. /*
  134.  * Skip over whitespace
  135.  */
  136. {
  137.     register int        c;
  138.  
  139.     do {                /* Skip whitespace    */
  140.         c = get();
  141. #if COMMENT_INVISIBLE
  142.     } while (type[c] == SPA || c == COM_SEP);
  143. #else
  144.     } while (type[c] == SPA);
  145. #endif
  146.     return (c);
  147. }
  148.  
  149. scanid(c)
  150. register int    c;                /* First char of id    */
  151. /*
  152.  * Get the next token (an id) into the token buffer.
  153.  * Note: this code is duplicated in lookid().
  154.  * Change one, change both.
  155.  */
  156. {
  157.     register char    *bp;
  158.  
  159.     if (c == DEF_MAGIC)            /* Eat the magic token    */
  160.         c = get();                /* undefiner.        */
  161.     bp = token;
  162.     do {
  163.         if (bp < &token[IDMAX])        /* token dim is IDMAX+1    */
  164.         *bp++ = c;
  165.         c = get();
  166.     } while (type[c] == LET || type[c] == DIG);
  167.     unget();
  168.     *bp = EOS;
  169. }
  170.  
  171. int
  172. macroid(c)
  173. register int        c;
  174. /*
  175.  * If c is a letter, scan the id.  if it's #defined, expand it and scan
  176.  * the next character and try again.
  177.  *
  178.  * Else, return the character.  If type[c] is a LET, the token is in token.
  179.  */
  180. {
  181.     register DEFBUF    *dp;
  182.  
  183.     if (infile != NULL && infile->fp != NULL)
  184.         recursion = 0;
  185.     while (type[c] == LET && (dp = lookid(c)) != NULL) {
  186.         expand(dp);
  187.         c = get();
  188.     }
  189.     return (c);
  190. }
  191.  
  192. int
  193. catenate()
  194. /*
  195.  * A token was just read (via macroid).
  196.  * If the next character is TOK_SEP, concatenate the next token
  197.  * return TRUE -- which should recall macroid after refreshing
  198.  * macroid's argument.  If it is not TOK_SEP, unget() the character
  199.  * and return FALSE.
  200.  */
  201. {
  202.     register int        c;
  203.     register char        *token1;
  204.  
  205. #if OK_CONCAT
  206.     if (get() != TOK_SEP) {            /* Token concatenation    */
  207.         unget();
  208.         return (FALSE);
  209.     }
  210.     else {
  211.         token1 = savestring(token);        /* Save first token    */
  212.         c = macroid(get());            /* Scan next token    */
  213.         switch(type[c]) {            /* What was it?        */
  214.         case LET:                /* An identifier, ...    */
  215.         if (strlen(token1) + strlen(token) >= NWORK)
  216.             cfatal("work buffer overflow doing %s #", token1);
  217.         sprintf(work, "%s%s", token1, token);
  218.         break;
  219.  
  220.         case DIG:                /* A digit string    */
  221.         strcpy(work, token1);
  222.         workp = work + strlen(work);
  223.         do {
  224.             save(c);
  225.         } while ((c = get()) != TOK_SEP);
  226.         /*
  227.          * The trailing TOK_SEP is no longer needed.
  228.          */
  229.         save(EOS);
  230.         break;
  231.  
  232.         default:                /* An error, ...    */
  233. #if ! COMMENT_INVISIBLE
  234.         if (isprint(c))
  235.             cierror("Strange character '%c' after #", c);
  236.         else
  237.             cierror("Strange character (%d.) after #", c);
  238. #endif
  239.         strcpy(work, token1);
  240.         unget();
  241.         break;
  242.         }
  243.         /*
  244.          * work has the concatenated token and token1 has
  245.          * the first token (no longer needed).  Unget the
  246.          * new (concatenated) token after freeing token1.
  247.          * Finally, setup to read the new token.
  248.          */
  249.         free(token1);            /* Free up memory    */
  250.         ungetstring(work);            /* Unget the new thing,    */
  251.         return (TRUE);
  252.     }
  253. #else
  254.     return (FALSE);                /* Not supported    */
  255. #endif
  256. }
  257.  
  258. int
  259. scanstring(delim, outfun)
  260. register int    delim;            /* ' or "            */
  261. int        (*outfun)();        /* Output function        */
  262. /*
  263.  * Scan off a string.  Warning if terminated by newline or EOF.
  264.  * outfun() outputs the character -- to a buffer if in a macro.
  265.  * TRUE if ok, FALSE if error.
  266.  */
  267. {
  268.     register int        c;
  269.  
  270.     instring = TRUE;        /* Don't strip comments        */
  271.     (*outfun)(delim);
  272.     while ((c = get()) != delim
  273.          && c != '\n'
  274.          && c != EOF_CHAR) {
  275.  
  276.         if (c != DEF_MAGIC)
  277.         (*outfun)(c);
  278.         if (c == '\\')
  279.         (*outfun)(get());
  280.     }
  281.     instring = FALSE;
  282.     if (c == delim) {
  283.         (*outfun)(c);
  284.         return (TRUE);
  285.     }
  286.     else {
  287.         cerror("Unterminated string", NULLST);
  288.         unget();
  289.         return (FALSE);
  290.     }
  291. }
  292.  
  293. scannumber(c, outfun)
  294. register int    c;                /* First char of number    */
  295. register int    (*outfun)();            /* Output/store func    */
  296. /*
  297.  * Process a number.  We know that c is from 0 to 9 or dot.
  298.  * Algorithm from Dave Conroy's Decus C.
  299.  */
  300. {
  301.     register int    radix;            /* 8, 10, or 16        */
  302.     int        expseen;        /* 'e' seen in floater    */
  303.     int        signseen;        /* '+' or '-' seen    */
  304.     int        octal89;        /* For bad octal test    */
  305.     int        dotflag;        /* TRUE if '.' was seen    */
  306.  
  307.     expseen = FALSE;            /* No exponent seen yet    */
  308.     signseen = TRUE;            /* No +/- allowed yet    */
  309.     octal89 = FALSE;            /* No bad octal yet    */
  310.     radix = 10;                /* Assume decimal    */
  311.     if ((dotflag = (c == '.')) != FALSE) {    /* . something?        */
  312.         (*outfun)('.');            /* Always out the dot    */
  313.         if (type[(c = get())] != DIG) {    /* If not a float numb,    */
  314.         unget();            /* Rescan strange char    */
  315.         return;                /* All done for now    */
  316.         }
  317.     }                    /* End of float test    */
  318.     else if (c == '0') {            /* Octal or hex?    */
  319.         (*outfun)(c);            /* Stuff initial zero    */
  320.         radix = 8;                /* Assume it's octal    */
  321.         c = get();                /* Look for an 'x'    */
  322.         if (c == 'x' || c == 'X') {        /* Did we get one?    */
  323.         radix = 16;            /* Remember new radix    */
  324.         (*outfun)(c);            /* Stuff the 'x'    */
  325.         c = get();            /* Get next character    */
  326.         }
  327.     }
  328.     for (;;) {                /* Process curr. char.    */
  329.         /*
  330.          * Note that this algorithm accepts "012e4" and "03.4"
  331.          * as legitimate floating-point numbers.
  332.          */
  333.         if (radix != 16 && (c == 'e' || c == 'E')) {
  334.         if (expseen)            /* Already saw 'E'?    */
  335.             break;            /* Exit loop, bad nbr.    */
  336.         expseen = TRUE;            /* Set exponent seen    */
  337.         signseen = FALSE;        /* We can read '+' now    */
  338.         radix = 10;            /* Decimal exponent    */
  339.         }
  340.         else if (radix != 16 && c == '.') {
  341.         if (dotflag)            /* Saw dot already?    */
  342.             break;            /* Exit loop, two dots    */
  343.         dotflag = TRUE;            /* Remember the dot    */
  344.         radix = 10;            /* Decimal fraction    */
  345.         }
  346.         else if (c == '+' || c == '-') {    /* 1.0e+10        */
  347.         if (signseen)            /* Sign in wrong place?    */
  348.             break;            /* Exit loop, not nbr.    */
  349.         /* signseen = TRUE; */        /* Remember we saw it    */
  350.         }
  351.         else {                /* Check the digit    */
  352.         switch (c) {
  353.         case '8': case '9':        /* Sometimes wrong    */
  354.             octal89 = TRUE;        /* Do check later    */
  355.         case '0': case '1': case '2': case '3':
  356.         case '4': case '5': case '6': case '7':
  357.             break;            /* Always ok        */
  358.  
  359.         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  360.         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
  361.             if (radix == 16)        /* Alpha's are ok only     */
  362.             break;            /* if reading hex.    */
  363.         default:            /* At number end    */
  364.             goto done;            /* Break from for loop    */
  365.         }                /* End of switch    */
  366.         }                    /* End general case    */
  367.         (*outfun)(c);            /* Accept the character    */
  368.         signseen = TRUE;            /* Don't read sign now    */
  369.         c = get();                /* Read another char    */
  370.     }                    /* End of scan loop    */
  371.     /*
  372.      * When we break out of the scan loop, c contains the first
  373.      * character (maybe) not in the number.  If the number is an
  374.      * integer, allow a trailing 'L' for long and/or a trailing 'U'
  375.      * for unsigned.  If not those, push the trailing character back
  376.      * on the input stream.  Floating point numbers accept a trailing
  377.      * 'L' for "long double".
  378.      */
  379. done:    if (dotflag || expseen) {        /* Floating point?    */
  380.         if (c == 'l' || c == 'L') {
  381.         (*outfun)(c);
  382.         c = get();            /* Ungotten later    */
  383.         }
  384.     }
  385.     else {                    /* Else it's an integer    */
  386.         /*
  387.          * We know that dotflag and expseen are both zero, now:
  388.          * dotflag signals "saw 'L'", and
  389.          * expseen signals "saw 'U'".
  390.          */
  391.         for (;;) {
  392.         switch (c) {
  393.         case 'l':
  394.         case 'L':
  395.             if (dotflag)
  396.             goto nomore;
  397.             dotflag = TRUE;
  398.             break;
  399.  
  400.         case 'u':
  401.         case 'U':
  402.             if (expseen)
  403.             goto nomore;
  404.             expseen = TRUE;
  405.             break;
  406.  
  407.         default:
  408.             goto nomore;
  409.         }
  410.         (*outfun)(c);            /* Got 'L' or 'U'.    */
  411.         c = get();            /* Look at next, too.    */
  412.         }
  413.     }
  414. nomore:    unget();                /* Not part of a number    */
  415.     if (octal89 && radix == 8)
  416.         cwarn("Illegal digit in octal number", NULLST);
  417. }
  418.  
  419. save(c)
  420. register int    c;
  421. {
  422.     if (workp >= &work[NWORK]) {
  423.         work[NWORK-1] = '\0';
  424.         cfatal("Work buffer overflow:  %s", work);
  425.     }
  426.     else *workp++ = c;
  427. }
  428.  
  429. char *
  430. savestring(text)
  431. char        *text;
  432. /*
  433.  * Store a string into free memory.
  434.  */
  435. {
  436.     register char    *result;
  437.  
  438.     result = getmem(strlen(text) + 1);
  439.     strcpy(result, text);
  440.     return (result);
  441. }
  442.  
  443. FILEINFO    *
  444. getfile(bufsize, name)
  445. int        bufsize;        /* Line or define buffer size    */
  446. char        *name;            /* File or macro name string    */
  447. /*
  448.  * Common FILEINFO buffer initialization for a new file or macro.
  449.  */
  450. {
  451.     register FILEINFO    *file;
  452.     register int        size;
  453.  
  454.     size = strlen(name);            /* File/macro name    */
  455.     file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size);
  456.     file->parent = infile;            /* Chain files together    */
  457.     file->fp = NULL;            /* No file yet        */
  458.     file->filename = savestring(name);    /* Save file/macro name    */
  459.     file->progname = NULL;            /* No #line seen yet    */
  460.     file->unrecur = 0;            /* No macro fixup    */
  461.     file->bptr = file->buffer;        /* Initialize line ptr    */
  462.     file->buffer[0] = EOS;            /* Force first read    */
  463.     file->line = 0;                /* (Not used just yet)    */
  464.     if (infile != NULL)            /* If #include file    */
  465.         infile->line = line;        /* Save current line    */
  466.     infile = file;                /* New current file    */
  467.     line = 1;                /* Note first line    */
  468.     return (file);                /* All done.        */
  469. }
  470.  
  471. char *
  472. getmem(size)
  473. int        size;
  474. /*
  475.  * Get a block of free memory.
  476.  */
  477. {
  478.     register char    *result;
  479.     extern char    *malloc();
  480.  
  481.     if ((result = malloc((unsigned) size)) == NULL)
  482.         cfatal("Out of memory", NULLST);
  483.     return (result);
  484. }
  485.  
  486. /*
  487.  *            C P P   S y m b o l   T a b l e s
  488.  */
  489.  
  490. /*
  491.  * SBSIZE defines the number of hash-table slots for the symbol table.
  492.  * It must be a power of 2.
  493.  */
  494. #ifndef    SBSIZE
  495. #define    SBSIZE    64
  496. #endif
  497. #define    SBMASK    (SBSIZE - 1)
  498. #if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1)
  499.     << error, SBSIZE must be a power of 2 >>
  500. #endif
  501.  
  502. static DEFBUF    *symtab[SBSIZE];    /* Symbol table queue headers    */
  503.  
  504. DEFBUF *
  505. lookid(c)
  506. int    c;                /* First character of token    */
  507. /*
  508.  * Look for the next token in the symbol table.  Returns token in "token".
  509.  * If found, returns the table pointer;  Else returns NULL.
  510.  */
  511. {
  512.     register int        nhash;
  513.     register DEFBUF        *dp;
  514.     register char        *np;
  515.     int            temp;
  516.     int            isrecurse;    /* For #define foo foo    */
  517.  
  518.     np = token;
  519.     nhash = 0;
  520.     if ((isrecurse = (c == DEF_MAGIC)))    /* If recursive macro    */
  521.         c = get();                /* hack, skip DEF_MAGIC    */
  522.     do {
  523.         if (np < &token[IDMAX]) {        /* token dim is IDMAX+1    */
  524.         *np++ = c;            /* Store token byte    */
  525.         nhash += c;            /* Update hash value    */
  526.         }
  527.         c = get();                /* And get another byte    */
  528.     } while (type[c] == LET || type[c] == DIG);
  529.     unget();                /* Rescan terminator    */
  530.     *np = EOS;                /* Terminate token    */
  531.     if (isrecurse)                /* Recursive definition    */
  532.         return (NULL);            /* undefined just now    */
  533.     nhash += (np - token);            /* Fix hash value    */
  534.     dp = symtab[nhash & SBMASK];        /* Starting bucket    */
  535.     while (dp != (DEFBUF *) NULL) {        /* Search symbol table    */
  536.         if (dp->hash == nhash        /* Fast precheck    */
  537.          && (temp = strcmp(dp->name, token)) >= 0)
  538.         break;
  539.         dp = dp->link;            /* Nope, try next one    */
  540.     }
  541.     return ((temp == 0) ? dp : NULL);
  542. }
  543.  
  544. DEFBUF *
  545. defendel(name, delete)
  546. char        *name;
  547. int        delete;            /* TRUE to delete a symbol    */
  548. /*
  549.  * Enter this name in the lookup table (delete = FALSE)
  550.  * or delete this name (delete = TRUE).
  551.  * Returns a pointer to the define block (delete = FALSE)
  552.  * Returns NULL if the symbol wasn't defined (delete = TRUE).
  553.  */
  554. {
  555.     register DEFBUF        *dp;
  556.     register DEFBUF        **prevp;
  557.     register char        *np;
  558.     int            nhash;
  559.     int            temp;
  560.     int            size;
  561.  
  562.     for (nhash = 0, np = name; *np != EOS;)
  563.         nhash += *np++;
  564.     size = (np - name);
  565.     nhash += size;
  566.     prevp = &symtab[nhash & SBMASK];
  567.     while ((dp = *prevp) != (DEFBUF *) NULL) {
  568.         if (dp->hash == nhash
  569.          && (temp = strcmp(dp->name, name)) >= 0) {
  570.         if (temp > 0)
  571.             dp = NULL;            /* Not found        */
  572.         else {
  573.             *prevp = dp->link;        /* Found, unlink and    */
  574.             if (dp->repl != NULL)    /* Free the replacement    */
  575.             free(dp->repl);        /* if any, and then    */
  576.             free((char *) dp);        /* Free the symbol    */
  577.         }
  578.         break;
  579.         }
  580.         prevp = &dp->link;
  581.     }
  582.     if (!delete) {
  583.         dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size);
  584.         dp->link = *prevp;
  585.         *prevp = dp;
  586.         dp->hash = nhash;
  587.         dp->repl = NULL;
  588.         dp->nargs = 0;
  589.         strcpy(dp->name, name);
  590.     }
  591.     return (dp);
  592. }
  593.  
  594. #if DEBUG
  595.  
  596. dumpdef(why)
  597. char        *why;
  598. {
  599.     register DEFBUF        *dp;
  600.     register DEFBUF        **syp;
  601.  
  602.     printf("CPP symbol table dump %s\n", why);
  603.     for (syp = symtab; syp < &symtab[SBSIZE]; syp++) {
  604.         if ((dp = *syp) != (DEFBUF *) NULL) {
  605.         printf("symtab[%d]\n", (syp - symtab));
  606.         do {
  607.             dumpadef((char *) NULL, dp);
  608.         } while ((dp = dp->link) != (DEFBUF *) NULL);
  609.         }
  610.     }
  611. }
  612.  
  613. dumpadef(why, dp)
  614. char        *why;            /* Notation            */
  615. register DEFBUF    *dp;
  616. {
  617.     register char        *cp;
  618.     register int        c;
  619.  
  620.     printf(" \"%s\" [%d]", dp->name, dp->nargs);
  621.     if (why != NULL)
  622.         printf(" (%s)", why);
  623.     if (dp->repl != NULL) {
  624.         printf(" => ");
  625.         for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) {
  626.         if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC))
  627.             printf("<%d>", c - MAC_PARM);
  628.         else if (c == DBL_QUOTE)
  629.             putchar('<">');    
  630.         else if (isprint(c) || c == '\n' || c == '\t')
  631.             putchar(c);
  632.         else if (c < ' ')
  633.             printf("<^%c>", c + '@');
  634.         else
  635.             printf("<\\0%o>", c);
  636.         }
  637.     }
  638.     else {
  639.         printf(", no replacement.");
  640.     }
  641.     putchar('\n');
  642. }
  643. #endif
  644.  
  645. /*
  646.  *            G E T
  647.  */
  648.  
  649. int
  650. get()
  651. /*
  652.  * Return the next character from a macro or the current file.
  653.  * Handle end of file from #include files.
  654.  */
  655. {
  656.     register int        c;
  657.     register FILEINFO    *file;
  658.     register int        popped;        /* Recursion fixup    */
  659.  
  660.     popped = 0;
  661. get_from_file:
  662.     if ((file = infile) == NULL)
  663.         return (EOF_CHAR);
  664. newline:
  665. #if 0
  666.     printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n",
  667.         file->filename, recursion, line,
  668.         file->bptr - file->buffer, file->buffer);
  669. #endif
  670.     /*
  671.      * Read a character from the current input line or macro.
  672.      * At EOS, either finish the current macro (freeing temp.
  673.      * storage) or read another line from the current input file.
  674.      * At EOF, exit the current file (#include) or, at EOF from
  675.      * the cpp input file, return EOF_CHAR to finish processing.
  676.      */
  677.     if ((c = *file->bptr++ & 0xFF) == EOS) {
  678.         /*
  679.          * Nothing in current line or macro.  Get next line (if
  680.          * input from a file), or do end of file/macro processing.
  681.          * In the latter case, jump back to restart from the top.
  682.          */
  683.         if (file->fp == NULL) {        /* NULL if macro    */
  684.         popped++;
  685.         recursion -= file->unrecur;
  686.         if (recursion < 0)
  687.             recursion = 0;
  688.         infile = file->parent;        /* Unwind file chain    */
  689.         }
  690.         else {                /* Else get from a file    */
  691.         if ((file->bptr = fgets(file->buffer, NBUFF, file->fp))
  692.             != NULL) {
  693. #if DEBUG
  694.             if (debug > 1) {        /* Dump it to stdout    */
  695.             printf("\n#line %d (%s), %s",
  696.                 line, file->filename, file->buffer);
  697.             }
  698. #endif
  699.             goto newline;        /* process the line    */
  700.         }
  701.         else {
  702. #if DEBUG
  703.                     if (debug)
  704.                         printf("\nclosing file %s",file->filename);
  705. #endif
  706.             fclose(file->fp);        /* Close finished file    */
  707.             if ((infile = file->parent) != NULL) {
  708.             /*
  709.              * There is an "ungotten" newline in the current
  710.              * infile buffer (set there by doinclude() in
  711.              * cpp1.c).  Thus, we know that the mainline code
  712.              * is skipping over blank lines and will do a
  713.              * #line at its convenience.
  714.              */
  715.             wrongline = TRUE;    /* Need a #line now    */
  716.             }
  717.         }
  718.         }
  719.         /*
  720.          * Free up space used by the (finished) file or macro and
  721.          * restart input from the parent file/macro, if any.
  722.          */
  723.         free(file->filename);        /* Free name and    */
  724.         if (file->progname != NULL)        /* if a #line was seen,    */
  725.         free(file->progname);        /* free it, too.    */
  726.         free((char *) file);        /* Free file space    */
  727.         if (infile == NULL)            /* If at end of file    */
  728.         return (EOF_CHAR);        /* Return end of file    */
  729.         line = infile->line;         /* Reset line number    */
  730.         goto get_from_file;            /* Get from the top.    */
  731.     }
  732.     /*
  733.      * Common processing for the new character.
  734.      */
  735.     if (c == DEF_MAGIC && file->fp != NULL)    /* Don't allow delete    */
  736.         goto newline;            /* from a file        */
  737.     if (file->parent != NULL) {        /* Macro or #include    */
  738.         if (popped != 0)
  739.         file->parent->unrecur += popped;
  740.         else {
  741.         recursion -= file->parent->unrecur;
  742.         if (recursion < 0)
  743.             recursion = 0;
  744.         file->parent->unrecur = 0;
  745.         }
  746.     }
  747.     if (c == '\n')                /* Maintain current    */
  748.         ++line;                /* line counter        */
  749.     if (instring)                /* Strings just return    */
  750.         return (c);                /* the character.    */
  751.     else if (c == '/') {            /* Comment?        */
  752.         instring = TRUE;            /* So get() won't loop    */
  753.         if ((c = get()) != '*') {        /* Next byte '*'?    */
  754.         instring = FALSE;        /* Nope, no comment    */
  755.         unget();            /* Push the char. back    */
  756.         return ('/');            /* Return the slash    */
  757.         }
  758.         if (keepcomments) {            /* If writing comments    */
  759.         putchar('/');            /* Write out the    */
  760.         putchar('*');            /*   initializer    */
  761.         }
  762.         for (;;) {                /* Eat a comment    */
  763.         c = get();
  764. test:        if (keepcomments && c != EOF_CHAR)
  765.             cput(c);
  766.         switch (c) {
  767.         case EOF_CHAR:
  768.             cerror("EOF in comment", NULLST);
  769.             return (EOF_CHAR);
  770.  
  771.         case '/':
  772.             if ((c = get()) != '*')    /* Don't let comments    */
  773.             goto test;        /* Nest.        */
  774. #ifdef STRICT_COMMENTS
  775.             cwarn("Nested comments", NULLST);
  776. #endif
  777.                         /* Fall into * stuff    */
  778.         case '*':
  779.             if ((c = get()) != '/')    /* If comment doesn't    */
  780.             goto test;        /* end, look at next    */
  781.             instring = FALSE;        /* End of comment,    */
  782.             if (keepcomments) {        /* Put out the comment    */
  783.             cput(c);        /* terminator, too    */
  784.             }
  785.             /*
  786.              * A comment is syntactically "whitespace" --
  787.              * however, there are certain strange sequences
  788.              * such as
  789.              *        #define foo(x)    (something)
  790.              *            foo|* comment *|(123)
  791.              *       these are '/' ^           ^
  792.              * where just returning space (or COM_SEP) will cause
  793.              * problems.  This can be "fixed" by overwriting the
  794.              * '/' in the input line buffer with ' ' (or COM_SEP)
  795.              * but that may mess up an error message.
  796.              * So, we peek ahead -- if the next character is
  797.              * "whitespace" we just get another character, if not,
  798.              * we modify the buffer.  All in the name of purity.
  799.              */
  800.             if (*file->bptr == '\n'
  801.              || type[*file->bptr & 0xFF] == SPA)
  802.             goto newline;
  803. #if COMMENT_INVISIBLE
  804.             /*
  805.              * Return magic (old-fashioned) syntactic space.
  806.              */
  807.             return ((file->bptr[-1] = COM_SEP));
  808. #else
  809.             return ((file->bptr[-1] = ' '));
  810. #endif
  811.  
  812.         case '\n':            /* we'll need a #line    */
  813.             if (!keepcomments)
  814.             wrongline = TRUE;    /* later...        */
  815.         default:            /* Anything else is    */
  816.             break;            /* Just a character    */
  817.         }                /* End switch        */
  818.         }                    /* End comment loop    */
  819.     }                    /* End if in comment    */
  820.     else if (!inmacro && c == '\\') {    /* If backslash, peek     */
  821.         if ((c = get()) == '\n') {        /* for a <nl>.  If so,    */
  822.         wrongline = TRUE;
  823.         goto newline;
  824.         }
  825.         else {                /* Backslash anything    */
  826.         unget();            /* Get it later        */
  827.         return ('\\');            /* Return the backslash    */
  828.         }
  829.     }
  830.     else if (c == '\f' || c == VT)        /* Form Feed, Vertical    */
  831.         c = ' ';                /* Tab are whitespace    */
  832.     return (c);                /* Just return the char    */
  833. }
  834.  
  835. unget()
  836. /*
  837.  * Backup the pointer to reread the last character.  Fatal error
  838.  * (code bug) if we backup too far.  unget() may be called,
  839.  * without problems, at end of file.  Only one character may
  840.  * be ungotten.  If you need to unget more, call ungetstring().
  841.  */
  842. {
  843.     register FILEINFO    *file;
  844.  
  845.     if ((file = infile) == NULL)
  846.         return;            /* Unget after EOF        */
  847.     if (--file->bptr < file->buffer)
  848.         cfatal("Too much pushback", NULLST);
  849.     if (*file->bptr == '\n')    /* Ungetting a newline?        */
  850.         --line;            /* Unget the line number, too    */
  851. }
  852.  
  853. ungetstring(text)
  854. char        *text;
  855. /*
  856.  * Push a string back on the input stream.  This is done by treating
  857.  * the text as if it were a macro.
  858.  */
  859. {
  860.     register FILEINFO    *file;
  861.     extern FILEINFO        *getfile();
  862.  
  863.     file = getfile(strlen(text) + 1, "");
  864.     strcpy(file->buffer, text);
  865. }
  866.  
  867. int
  868. cget()
  869. /*
  870.  * Get one character, absorb "funny space" after comments or
  871.  * token concatenation
  872.  */
  873. {
  874.     register int    c;
  875.  
  876.     do {
  877.         c = get();
  878. #if COMMENT_INVISIBLE
  879.     } while (c == TOK_SEP || c == COM_SEP);
  880. #else
  881.     } while (c == TOK_SEP);
  882. #endif
  883.     return (c);
  884. }
  885.  
  886. /*
  887.  * Error messages and other hacks.  The first byte of severity
  888.  * is 'S' for string arguments and 'I' for int arguments.  This
  889.  * is needed for portability with machines that have int's that
  890.  * are shorter than  char *'s.
  891.  */
  892.  
  893. static
  894. domsg(severity, format, arg)
  895. char        *severity;        /* "Error", "Warning", "Fatal"    */
  896. char        *format;        /* Format for the error message    */
  897. char        *arg;            /* Something for the message    */
  898. /*
  899.  * Print filenames, macro names, and line numbers for error messages.
  900.  */
  901. {
  902.     register char        *tp;
  903.     register FILEINFO    *file;
  904.  
  905.     fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]);
  906.     if (*severity == 'S')
  907.         fprintf(stderr, format, arg);
  908.     else
  909.         fprintf(stderr, format, (int) arg);
  910.     putc('\n', stderr);
  911.     if ((file = infile) == NULL)
  912.         return;                /* At end of file    */
  913.     if (file->fp != NULL) {
  914.         tp = file->buffer;            /* Print current file    */
  915.         fprintf(stderr, "%s", tp);        /* name, making sure    */
  916.         if (tp[strlen(tp) - 1] != '\n')    /* there's a newline    */
  917.         putc('\n', stderr);
  918.     }
  919.     while ((file = file->parent) != NULL) {    /* Print #includes, too    */
  920.         if (file->fp == NULL)
  921.         fprintf(stderr, "from macro %s\n", file->filename);
  922.         else {
  923.         tp = file->buffer;
  924.         fprintf(stderr, "from file %s, line %d:\n%s",
  925.             (file->progname != NULL)
  926.             ? file->progname : file->filename,
  927.             file->line, tp);
  928.         if (tp[strlen(tp) - 1] != '\n')
  929.             putc('\n', stderr);
  930.         }
  931.     }
  932. }
  933.  
  934. cerror(format, sarg)
  935. char        *format;
  936. char        *sarg;        /* Single string argument        */
  937. /*
  938.  * Print a normal error message, string argument.
  939.  */
  940. {
  941.     domsg("SError", format, sarg);
  942.     errors++;
  943. }
  944.  
  945. cierror(format, narg)
  946. char        *format;
  947. int        narg;        /* Single numeric argument        */
  948. /*
  949.  * Print a normal error message, numeric argument.
  950.  */
  951. {
  952.     domsg("IError", format, (char *) narg);
  953.     errors++;
  954. }
  955.  
  956. cfatal(format, sarg)
  957. char        *format;
  958. char        *sarg;            /* Single string argument    */
  959. /*
  960.  * A real disaster
  961.  */
  962. {
  963.     domsg("SFatal error", format, sarg);
  964.     exit(IO_ERROR);
  965. }
  966.  
  967. cwarn(format, sarg)
  968. char        *format;
  969. char        *sarg;            /* Single string argument    */
  970. /*
  971.  * A non-fatal error, string argument.
  972.  */
  973. {
  974.     domsg("SWarning", format, sarg);
  975. }
  976.  
  977. ciwarn(format, narg)
  978. char        *format;
  979. int        narg;            /* Single numeric argument    */
  980. /*
  981.  * A non-fatal error, numeric argument.
  982.  */
  983. {
  984.     domsg("IWarning", format, (char *) narg);
  985. }
  986.  
  987.  
  988.  
  989.